﻿<!DOCTYPE html>
<html>
<head>
<!--
  Copyright (c) 2015 Jean-Marc VIGLINO,
  released under CeCILL-B (french BSD like) licence: http://www.cecill.info/
-->
  <title>ol-ext: LayerShop</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

  <meta name="description" content="An OL3 layerswitcher." />
  <meta name="keywords" content="openlayers, ol, layer, layerswitcher, control" />

  <!-- jQuery -->
  <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
  <!-- FontAwesome -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

  <!-- Openlayers -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@latest/ol.css" />
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ol@latest/dist/ol.js"></script>

  
  <!-- ol-ext -->
  <link rel="stylesheet" href="../../dist/ol-ext.css" />
  <script type="text/javascript" src="../../dist/ol-ext.js"></script>
  <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
  <script src="https://unpkg.com/elm-pep"></script>

  <link rel="stylesheet" href="../style.css" />
  <style>
    .ol-layer-shop i {
      color: inherit;
      font-size: 1.3em;
    }
    /*
    textarea:focus, input:focus, select:focus {
      outline: none;
    }
    */
    /* Remove opacity */
    .layerswitcher-opacity {
      display: none;
    }
    .ol-layer-shop .ol-bar input[type="number"] {
      width: 3em;
      height: 1em;
    }
    #map:focus-visible {
      outline: 2px solid #369;
    }
    button:focus-visible {
      outline: solid!important;
    }
    .ol-bar button:focus-visible {
      position: relative;
      z-index: 1;
    }
  </style>
</head>
<body >
  <a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>

  <a href="../../index.html">
    <h1>ol-ext: LayerShop control</h1>
  </a>
  <div class="info">
    <b>ol/control/LayerShop</b> is a layer switcher integrating tool bars to handle layers properties.
  </div>

  <!-- Map div -->
  <div id="map" style="width: 100%; height: 400px;" tabindex="0"></div>
  <div class="options">
  </div>
  
  <script type="text/javascript">

  // A group layer for base layers
  var baseLayers = new ol.layer.Group({
    title: 'Base Layers',
    openInLayerSwitcher: true,
    layers: [
    new ol.layer.Geoportail({
        baseLayer: true,
        visible: false,
        layer: 'ORTHOIMAGERY.ORTHOPHOTOS'
      }),
      new ol.layer.Geoportail({
        baseLayer: true,
        layer: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2'
      }),
      new ol.layer.Tile({
        title: "OSM",
        baseLayer: true,
        source: new ol.source.OSM(),
        visible: false
      })
    ]
  });
  ol.layer.Geoportail.register("LANDCOVER.CLC18", {"layer":"LANDCOVER.CLC18","theme":"clc","desc":"Inventaire biophysique de l'occupation des sols en 2018 en 50 postes pour les DOM et 44 postes pour la Métropole. CORINE Land Cover est une base de données d’occupation des sols produite dans le cadre du programme européen d’observation de la Terre Copernicus. Cet inventaire biophysique de l’occupation des terres fournit une information géographique de référence pour 39 États européens. La continuité du programme et la diffusion des données CORINE Land Cover sont pilotées par l'Agence européenne pour l'environnement. Le producteur pour la France est le Service de la donnée et des études statistiques du ministère chargé de l’écologie. L'utilisation de cette base de données permet des applications variées adaptées aux problématiques de l'environnement et à celles de l'aménagement du territoire : production cartographique, exploitation à des fins statistiques ou bien encore analyses géographiques en combinaison avec d'autres bases de données. Outil de connaissance et d'analyse, CORINE Land Cover apporte également une aide à la décision comme instrument de suivi, de surveillance et de gestion de l'environnement, des milieux naturels et de l'aménagement de l'espace. La base de données CORINE Land Cover 2018 a été réalisée à partir de CORINE Land Cover 2012 révisée et de la base des changements 2012-2018.","server":"https://data.geopf.fr/wmts","bbox":[-63.3725,-21.4756,55.9259,51.4428],"format":"image/png","minZoom":0,"maxZoom":16,"originators":{"Geoservices":{"attribution":"Géoservices","href":"https://geoservices.ign.fr/"}},"queryable":false,"style":"CORINE Land Cover","tilematrix":"PM","title":"CORINE Land Cover - 2018"});
  var clc = new ol.layer.Geoportail({ 
    layer: 'LANDCOVER.CLC18', 
    //className: 'clc' 
  });
  // The Map
  var map = new ol.Map({
    target: 'map',
    view: new ol.View({
      zoom: 11,
      center: [260497, 6249720]
    }),
    layers: [ 
      baseLayers, 
      new ol.layer.Geoportail({ 
        layer: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2', 
        className: 'PLANIGNV2',
        visible: false 
      }),
      new ol.layer.Geoportail({ 
        layer: 'ORTHOIMAGERY.ORTHOPHOTOS', 
        className: 'ORTHOPHOTOS' 
      }),
      new ol.layer.Geoportail({ 
        layer: 'CADASTRALPARCELS.PARCELLAIRE_EXPRESS',
        className: 'PARCELLAIRE_EXPRESS' 
      }),
      clc,
      new ol.layer.Geoportail({
        title: 'Labels',
        className: 'Labels',
        layer: 'GEOGRAPHICALNAMES.NAMES'
      }) 
    ]
  });

  // Add control inside the map
  var ctrl = new ol.control.LayerShop({
    counter: true,
    minibar: true
  });
  map.addControl(ctrl);
  
  // WMS control
  var wms = new ol.control.WMSCapabilities({ 
    target: document.body,
    title: 'Add WMS',
    services: {
      'BRGM': 'https://geoservices.brgm.fr/geologie',
      'OSM': 'https://wms.openstreetmap.fr/wms',
      'OSM-Mundialis': 'https://ows.mundialis.de/services/service',
      'IGN-Géoservices': 'https://data.geopf.fr/wms-r/wms'
    },
    onselect: function(layer) {
      var index = map.getLayers().getArray().indexOf(ctrl.getSelection());
      map.getLayers().insertAt(index+1, layer);
      ctrl.selectLayer(layer);
    }
  });
  ctrl.addControl(wms, 'bottom');

  // Remove layer button
  ctrl.addControl(new ol.control.Button({
    html: '<i class="fa fa-trash-o"></i>',
    title: 'Remove layer',
    handleClick: function() {
      map.removeLayer(ctrl.getSelection());
    }
  }), 'bottom');
  
  // Info dialogue
  var dlg = new ol.control.Dialog({ closeBox: true, hideOnBack: true, fullscreen: true });
  map.addControl(dlg);
  // Show info
  ctrl.addControl(new ol.control.Button({
    html: '<i class="fa fa-info-circle"></i>',
    title: 'Information',
    handleClick: function() {
      var d = $('<div>');
      var layer = ctrl.getSelection();
      if (layer) {
        $('<h2>').text(layer.get('title')).appendTo(d);
        $('<p>').text(layer.get('desc') || layer.get('abstract')).appendTo(d);
        if (layer.getSource && layer.getSource()) {
          $('<div>').html(layer.getSource().getAttributions()().join('<br/>')).appendTo(d);
        }
        dlg.show(d.get(0));
      }
    }
  }), 'bottom');

  // Mix blend Menu
  var blendFilter = {
    multiply: new ol.filter.CSS({ blend: 'multiply' }),
    luminosity: new ol.filter.CSS({ blend: 'luminosity' }),
    color: new ol.filter.CSS({ blend: 'color' }),
    'color-burn': new ol.filter.CSS({ blend: 'color-burn' }),
    difference: new ol.filter.CSS({ blend: 'difference' }),
    overlay: new ol.filter.CSS({ blend: 'overlay' })
  };
  clc.addFilter(blendFilter.multiply);
  // Add selector
  var blend = ol.ext.element.create('SELECT', { 
    options: {
      'Mode' : '',
      'Multiply' : 'multiply',
      'Luminosity' : 'luminosity',
      'Color' : 'color',
      'Color burn' : 'color-burn',
      'Difference' : 'difference',
      'Overlay' : 'overlay'
    },
    on: {
      change: function(e) {
        for (var i in blendFilter) ctrl.getSelection().removeFilter(blendFilter[i]);
        if (blendFilter[blend.value]) ctrl.getSelection().addFilter(blendFilter[blend.value]);
      }
    },
    parent: ctrl.getBarElement()
  });
  // Update filter on select layer
  ctrl.on('select', function(e) {
    blend.value = '';
    for (var i in blendFilter) {
      if (ctrl.getSelection().getFilters().indexOf(blendFilter[i]) >= 0) blend.value = i;
    }
  });

  // Grayscale filter menu
  var filter = new ol.filter.Colorize('grayscale');
  filter.set('preserveAlpha', true);
  var sel = ol.ext.element.create('SELECT', { 
    options: {
      'Filter' : 'normal',
      'Grayscale' : 'grayscale'
    },
    on: {
      change: function() {
        if (ctrl.getSelection().getFilters().indexOf(filter) < 0) ctrl.getSelection().addFilter(filter);
        else ctrl.getSelection().removeFilter(filter);
      }
    },
    parent: ctrl.getBarElement()
  });
  // Update filter on select layer
  ctrl.on('select', function(e) {
    if (ctrl.getSelection().getFilters().indexOf(filter) < 0) sel.value = 'normal';
    else sel.value = 'grayscale';
  });

  // Opacity slider
  var opacity = new ol.ext.input.Slider({
    className: 'opacity',
    align: 'right',
    type: 'number',
    min: 0,
    max: 100,
    parent: ctrl.getBarElement()
  });
  opacity.on('change:value', function(e) {
    ctrl.getSelection().setOpacity(e.value/100);
  })
  ctrl.on(['layer:opacity', 'select'], function(e) {
    if (e.layer === ctrl.getSelection()) {
      opacity.setValue(Math.round(e.layer.getOpacity()*100));
    }
  });

  // Select first layer
  ctrl.selectLayer();
  </script>
  
</body>
</html>